package order

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	userx "mall/common/utils/user"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/order/rpc/orderclient"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetOrderByIdLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetOrderByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderByIdLogic {
	return &GetOrderByIdLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetOrderByIdLogic) GetOrderById(
	req *types.OrderIdReq,
	headers *[]*types.Header,
) (resp *types.TradeInfo, err error) {
	if (req.Id == nil || *req.Id == 0) && (req.Sn == nil || len(strings.TrimSpace(*req.Sn)) == 0) {
		return nil, resultx.NewErrCode(resultx.REUQEST_PARAM_ERROR)
	}

	userId := jwt.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	preload := "order:Id,Sn,OrderType,TradeState,Quantity,GemAmount,RetailAmount,Freight,DiscountAmount,AdjustAmount,ActualAmount,Amount,RefundAmount"
	preload += ",Gems,Remark,CreatedAt,UpdatedAt,PaidAt,ShippedAt,DeliveredAt,ConfirmedAt,ReviewedAt,ClosedAt,Comments,Growth,Integrals"
	preload += ";orderItem:Id,SkuId,Sku,ImageUrl,ProductId,EntryId,Title,Slug,ProductType,BrandId,BrandTitle,BrandSlug"
	preload += ",GemPrice,RetailPrice,Quantity,Weight,TradeState,Status,RefundQuantity"
	preload += ";orderAddress:UserId,Consignee,Mobile,Province,City,District,Address,PostalCode,Label"
	preload += ";orderPayment:No,Amount,Type,Name,Code,PaidAt"
	preload += ";orderShipment:No,Type,Name,Code,UpdatedAt"
	preload += ";orderDiscount:SkuId,ProductId,Title,Slug,ActivityId,ActivityRuleId,CouponTemplateId,CouponId,CouponAmount,ActivityAmount"
	preload += ",IntegralAmount,DiscountAmount,Integrals"
	preload += ";orderAdjustment:Amount"
	eagerLoad := "order:orderItem,orderAddress,orderPayment,orderShipment,orderDiscount,orderAdjustment"
	var filters []string
	if req.Id != nil && *req.Id > 0 {
		filters = append(filters, "Id,equalTo:"+strconv.FormatInt(int64(*req.Id), 10))
	} else {
		filters = append(filters, "Sn,equalTo:"+strings.TrimSpace(*req.Sn))
	}
	filters = append(filters, "UserId,equalTo:"+strconv.FormatInt(int64(userId), 10))
	var platformId uint32 = globalkey.ThirdPartyPlatformWechatMini

	res, err := l.svcCtx.OrderRpc.GetOrderById(l.ctx, &orderclient.BaseIdReq{
		Id:         req.Id,
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		logx.Errorw("GetOrderById err", logx.Field("detail", err.Error()))
		return &types.TradeInfo{}, nil
	}

	// logrus.Info(fmt.Sprintf("GetOrderById: %+v", res))

	if res == nil || res.Id == nil || *res.Id == 0 {
		// return nil, resultx.NewErrCode(resultx.ORDER_PARAM_INVALID)
		return &types.TradeInfo{}, nil
	}

	orderTypeText := util.GetOrderTypeText(res.OrderType)
	orderTradeStateText := util.GetTradeStateText(res.TradeState)

	var skus []*types.OrderSkuInfo
	if len(res.Skus) > 0 {
		for _, v := range res.Skus {
			productTypeText := util.GetProductTypeText(v.ProductType)
			skus = append(skus, &types.OrderSkuInfo{
				Id:             v.Id,
				OrderId:        v.OrderId,
				ProductCode:    v.ProductCode,
				SkuId:          v.SkuId,
				SkuCode:        v.SkuCode,
				Sku:            v.Sku,
				ImageId:        v.ImageId,
				ImageUrl:       v.ImageUrl,
				ProductId:      v.ProductId,
				EntryId:        v.EntryId,
				Title:          v.Title,
				Slug:           v.Slug,
				ProductType:    v.ProductType,
				TypeText:       productTypeText,
				BrandId:        v.BrandId,
				BrandTitle:     v.BrandTitle,
				BrandSlug:      v.BrandSlug,
				GemPrice:       v.GemPrice,
				RetailPrice:    v.RetailPrice,
				Quantity:       v.Quantity,
				Weight:         v.Weight,
				TradeState:     v.TradeState,
				Status:         v.Status,
				RefundAmount:   v.RefundAmount,
				RefundQuantity: v.RefundQuantity,
			})
		}
	}
	var addresses []*types.OrderAddressInfo
	if len(res.Addresses) > 0 {
		for _, v := range res.Addresses {
			var mobile *string
			if v.Mobile != nil {
				mobile = pointy.GetPointer(userx.UserMsgEncipher(*v.Mobile, userx.MODEL))
			}

			addresses = append(addresses, &types.OrderAddressInfo{
				Id:         v.Id,
				OrderId:    v.OrderId,
				UserId:     v.UserId,
				Consignee:  v.Consignee,
				Mobile:     mobile,
				Province:   v.Province,
				City:       v.City,
				District:   v.District,
				Address:    v.Address,
				PostalCode: v.PostalCode,
				RegionCode: v.RegionCode,
				Label:      v.Label,
			})
		}
	}
	var discounts []*types.OrderDiscountInfo
	if len(res.Discounts) > 0 {
		for _, v := range res.Discounts {
			discounts = append(discounts, &types.OrderDiscountInfo{
				Id:               v.Id,
				OrderId:          v.OrderId,
				SkuId:            v.SkuId,
				ProductId:        v.ProductId,
				Title:            v.Title,
				Slug:             v.Slug,
				ActivityId:       v.ActivityId,
				ActivityRuleId:   v.ActivityRuleId,
				CouponTemplateId: v.CouponTemplateId,
				CouponId:         v.CouponId,
				CouponAmount:     v.CouponAmount,
				ActivityAmount:   v.ActivityAmount,
				IntegralAmount:   v.IntegralAmount,
				DiscountAmount:   v.DiscountAmount,
				Integrals:        v.Integrals,
			})
		}
	}
	var adjustments []*types.OrderAdjustmentInfo
	if len(res.Adjustments) > 0 {
		for _, v := range res.Adjustments {
			adjustments = append(adjustments, &types.OrderAdjustmentInfo{
				Id:      v.Id,
				OrderId: v.OrderId,
				Amount:  v.Amount,
			})
		}
	}
	var payments []*types.OrderPaymentInfo
	if len(res.Payments) > 0 {
		for _, v := range res.Payments {
			payments = append(payments, &types.OrderPaymentInfo{
				Id:      v.Id,
				OrderId: v.OrderId,
				No:      v.No,
				Amount:  v.Amount,
				Type:    v.Type,
				Name:    v.Name,
				Code:    v.Code,
				PaidAt:  v.PaidAt,
			})
		}
	}
	var shipments []*types.OrderShipmentInfo
	if len(res.Shipments) > 0 {
		for _, v := range res.Shipments {
			shipments = append(shipments, &types.OrderShipmentInfo{
				Id:        v.Id,
				OrderId:   v.OrderId,
				No:        v.No,
				Type:      v.Type,
				Name:      v.Name,
				Code:      v.Code,
				UpdatedAt: v.UpdatedAt,
			})
		}
	}

	option := util.GetOptionByStatus(res.TradeState)
	var canPayText *string
	if option.CanPay && res.CreatedAt != nil {
		canPayText = pointy.GetPointer(util.GetCanPayText(*res.CreatedAt))
	}

	return &types.TradeInfo{
		Id:              res.Id,
		ParentId:        res.ParentId,
		UserId:          res.UserId,
		UserRank:        res.UserRank,
		Buyer:           res.Buyer,
		Sn:              res.Sn,
		OrderType:       res.OrderType,
		OrderTypeText:   orderTypeText,
		Total:           res.Number,
		GemAmount:       res.GemAmount,
		RetailAmount:    res.RetailAmount,
		Freight:         res.Freight,
		DiscountAmount:  res.DiscountAmount,
		AdjustAmount:    res.AdjustAmount,
		ActualAmount:    res.ActualAmount,
		BalanceAmount:   res.BalanceAmount,
		RefundAmount:    res.RefundAmount,
		Gems:            res.Gems,
		TradeState:      res.TradeState,
		TradeStateText:  orderTradeStateText,
		Remark:          res.Remark,
		CreatedAt:       res.CreatedAt,
		UpdatedAt:       res.UpdatedAt,
		PaidAt:          res.PaidAt,
		ShippedAt:       res.ShippedAt,
		DeliveredAt:     res.DeliveredAt,
		ConfirmedAt:     res.ConfirmedAt,
		ReviewedAt:      res.ReviewedAt,
		FulfilledAt:     res.FulfilledAt,
		ClosedAt:        res.ClosedAt,
		AutoComfirmDays: res.AutoComfirmDays,
		Growth:          res.Growth,
		Integrals:       res.Integrals,
		Skus:            skus,
		Addresses:       addresses,
		Discounts:       discounts,
		Adjustments:     adjustments,
		Payments:        payments,
		Shipments:       shipments,

		CanCancel:  option.CanCancel,
		CanPay:     option.CanPay,
		CanRefund:  option.CanRefund,
		CanRemind:  option.CanRemind,
		CanTrack:   option.CanTrack,
		CanConfirm: option.CanConfirm,
		CanInvoice: option.CanInvoice,
		CanRemove:  option.CanRemove,
		CanPayText: canPayText,
	}, nil
}
